/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * PcaInternalFrame.java
 *
 * Created on 13.07.2010, 17:25:24
 */
package GUI.iFrames;

import java.util.List;
import java.util.Vector;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import toolz.PCA;
import toolz.PCA.PrincipleComponent;
import DATA.iDataSet;
import DATA.iDataSetParts.Measurement;
import GUI.BaseFrame;
import GUI.iFrames.DataSourceComponents.DataSourcesInternalFrame;
import Jama.Matrix;

/**
 * 
 * @author Bunkowski
 */
public class PcaInternalFrame extends javax.swing.JInternalFrame {

	public static final long serialVersionUID = 1L;

	private XYSeriesCollection dataset = new XYSeriesCollection();
	private Vector<PcaMeasurementElement> pmes = new Vector<PcaMeasurementElement>();
	private DataSourcesInternalFrame dif;
	private Vector<String> MeasurementIDs = new Vector<String>();
	private Vector<String> classLabels = new Vector<String>();
	private Vector<String> labels = new Vector<String>();
	private XYPlot plot;
	private ChartPanel cp;

	/** Creates new form PcaInternalFrame */
	public PcaInternalFrame(DataSourcesInternalFrame dif) {
		initComponents();
		this.dif = dif;
		init();

	}

	// ArrayList<String> categories = new ArrayList<String>();
	//
	// if (classLabels == null) {
	// classLabels = new Vector<String>();
	// for (int i = 0; i <
	// dif.table.getRowCount(); i++) {
	// classLabels.add("all");
	// }
	//
	// }
	//
	// for (String s : classLabels) {
	// if (!categories.contains(s)) {
	// categories.add(s);
	// }
	//
	// }
	private void init() {
		Matrix out = getPca();

		double[][] arrayOut = out.getArray();

		System.out.println(arrayOut.length + " x " + arrayOut[0].length);

		for (int i = 0; i < arrayOut.length; i++) {

			String MeasurementID;
			Vector<Double> PCs = new Vector<Double>();
			String label;
			String clas;

			label = labels.get(i);
			clas = classLabels.get(i);
			MeasurementID = MeasurementIDs.get(i);

			for (int j = 0; j < arrayOut[0].length; j++) {
				double d = arrayOut[i][j];
				PCs.add(d);
			}
			PcaMeasurementElement pme = new PcaMeasurementElement(dif.idataset, MeasurementID, PCs, label, clas);
			pmes.add(pme);
		}

		int xIdx = Integer.parseInt(xAxisComboBox.getSelectedItem().toString().replace("PC", ""));
		int yIdx = Integer.parseInt(yAxisComboBox.getSelectedItem().toString().replace("PC", ""));

		for (int i = 0; i < pmes.size(); i++) {
			PcaMeasurementElement pme = pmes.elementAt(i);
			try {
				dataset.getSeries(pme.clas);
			} catch (Exception exc) {
				dataset.addSeries(new XYSeries(pme.clas));
			}
			double x = pme.PCs.get(xIdx - 1);
			double y = pme.PCs.get(yIdx - 1);
			dataset.getSeries(pme.clas).add(x, y);
		}

		center.removeAll();

		NumberAxis xAxis = new NumberAxis("x");
		NumberAxis yAxis = new NumberAxis("y");

		XYItemRenderer rend = new XYLineAndShapeRenderer(false, true);
		plot = new XYPlot(dataset, xAxis, yAxis, rend);
		JFreeChart chart = new JFreeChart(plot);
		cp = new ChartPanel(chart);
		center.add(cp);

		BaseFrame.applyFrame(this);
		this.moveToFront();
		this.show();

	}

	private void update() {
		dataset.removeAllSeries();
		int xIdx = Integer.parseInt(xAxisComboBox.getSelectedItem().toString().replace("PC", ""));
		int yIdx = Integer.parseInt(yAxisComboBox.getSelectedItem().toString().replace("PC", ""));

		for (int i = 0; i < pmes.size(); i++) {
			PcaMeasurementElement pme = pmes.elementAt(i);
			try {
				dataset.getSeries(pme.clas);
			} catch (Exception exc) {
				dataset.addSeries(new XYSeries(pme.clas));
			}
			double x = pme.PCs.get(xIdx - 1);
			double y = pme.PCs.get(yIdx - 1);
			dataset.getSeries(pme.clas).add(x, y);
		}

	}

	private Matrix getPca() {
		int[] selectedColumns = dif.table.getSelectedColumns();
		int rowCount = dif.table.getRowCount();

		double[][] matrix = new double[rowCount][selectedColumns.length];

		for (int y = 0; y < rowCount; y++) {
			MeasurementIDs.add(dif.table.getValueAt(y, 1).toString());

			if (dif.selectedLabel != -1) {
				labels.add(dif.getSelectedLabelColumn().get(y));
			} else {
				labels.add("");
			}

			if (dif.selectedClasses != -1) {
				classLabels.add(dif.getSelectedClassColumn().get(y));
			} else {
				classLabels.add("");
			}

			for (int x = 0; x < selectedColumns.length; x++) {
				int sx = selectedColumns[x];
				String stringValue = dif.table.getValueAt(y, sx).toString().replace(",", ".");
				double value = 0;
				try {
					value = Double.parseDouble(stringValue);
				} catch (Exception exc) {
					System.out.println("double casting of [" + stringValue + "] failed");
				}

				matrix[y][x] = value;
			}

		}

		// Matrix originalData = new Matrix(matrix);
		PCA pca = new PCA(matrix);
		// int numComponents = pca.getNumComponents();
		int k = 10;
		List<PrincipleComponent> mainComponents = pca.getDominantComponents(k);
		Matrix features = PCA.getDominantComponentsMatrix(mainComponents);
		Matrix featuresXpose = features.transpose();

		double[][] matrixAdjusted = PCA.getMeanAdjusted(matrix, pca.getMeans());
		Matrix adjustedInput = new Matrix(matrixAdjusted);
		Matrix xformedData = featuresXpose.times(adjustedInput.transpose());
		// xformedData.transpose().print(8, 4);

		Matrix out = xformedData.transpose();

		return out;
	}

	/**
	 * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
	 * content of this method is always regenerated by the Form Editor.
	 */
	private void initComponents() {

		center = new javax.swing.JPanel();
		jLabel1 = new javax.swing.JLabel();
		jLabel2 = new javax.swing.JLabel();
		xAxisComboBox = new javax.swing.JComboBox();
		yAxisComboBox = new javax.swing.JComboBox();

		setClosable(true);
		setIconifiable(true);
		setMaximizable(true);
		setResizable(true);
		setTitle("PCA");

		center.setLayout(new javax.swing.BoxLayout(center, javax.swing.BoxLayout.Y_AXIS));

		jLabel1.setText("X-Axis:");

		jLabel2.setText("Y-Axis:");

		xAxisComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "PC1", "PC2", "PC3", "PC4", "PC5",
				"PC6", "PC7", "PC8", "PC9", "PC10" }));
		xAxisComboBox.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				xAxisComboBoxActionPerformed(evt);
			}
		});

		yAxisComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "PC1", "PC2", "PC3", "PC4", "PC5",
				"PC6", "PC7", "PC8", "PC9", "PC10" }));
		yAxisComboBox.setSelectedItem(yAxisComboBox.getItemAt(1));
		yAxisComboBox.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				yAxisComboBoxActionPerformed(evt);
			}
		});

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
		getContentPane().setLayout(layout);
		layout.setHorizontalGroup(layout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGroup(
						layout.createSequentialGroup()
								.addContainerGap()
								.addComponent(jLabel1)
								.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
								.addComponent(xAxisComboBox, javax.swing.GroupLayout.PREFERRED_SIZE,
										javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
								.addGap(15, 15, 15)
								.addComponent(jLabel2)
								.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
								.addComponent(yAxisComboBox, javax.swing.GroupLayout.PREFERRED_SIZE,
										javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
								.addContainerGap(193, Short.MAX_VALUE))
				.addComponent(center, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE));
		layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				layout.createSequentialGroup()
						.addContainerGap()
						.addGroup(
								layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
										.addComponent(jLabel1)
										.addComponent(jLabel2)
										.addComponent(xAxisComboBox, javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addComponent(yAxisComboBox, javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
						.addComponent(center, javax.swing.GroupLayout.DEFAULT_SIZE, 245, Short.MAX_VALUE)));

		pack();
	}// </editor-fold>//GEN-END:initComponents

	private void yAxisComboBoxActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_yAxisComboBoxActionPerformed
		update();
	}// GEN-LAST:event_yAxisComboBoxActionPerformed

	private void xAxisComboBoxActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_xAxisComboBoxActionPerformed
		update();
	}// GEN-LAST:event_xAxisComboBoxActionPerformed

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.JPanel center;
	private javax.swing.JLabel jLabel1;
	private javax.swing.JLabel jLabel2;
	private javax.swing.JComboBox xAxisComboBox;
	private javax.swing.JComboBox yAxisComboBox;
	// End of variables declaration//GEN-END:variables
}

class PcaMeasurementElement {

	public String MeasurementID;
	public Vector<Double> PCs;
	public String label;
	public String clas;
	public Measurement measurement;

	public PcaMeasurementElement(iDataSet dataSet, String MeasurementID, Vector<Double> PCs, String label, String clas) {
		this.MeasurementID = MeasurementID;
		this.PCs = PCs;
		this.label = label;
		this.clas = clas;
		for (Measurement m : dataSet.measurements) {
			if (m.measurementID.equals(MeasurementID)) {
				this.measurement = m;
				break;
			}
		}

	}
}
